/* ---------------------------- definitions --------------------------------- */


%top{

/*
 * Departamento de Ciência da Computação
 * Tradutores 02/2009 - turma A
 * Professor Marco Aurélio
 * Alunos: Danilo Gaby Andersen Trindade - 06/82039
 *         Alex Rodrigo de Oliveira      - 06/30403
 */

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include "tokens.h"
    #include "scanner.h"

    using namespace std;

    int here;

    static int indent();
    static int str(const char *txt);
    static void error(const char* txt);
    vector<int> indstack;
}

ws              " "|"\t"
letra           [A-Za-z_]
digito          [0-9]
int             {digito}+
id              {letra}({letra}|{digito})*
err             [@#$]|"."

%x IND


%%  /* -------------------------- rules ------------------------------------- */


%{
    int indtok;
%}

^{ws}*"\n"      { here++; }
"\n"            { here++; BEGIN(IND); return NEWLINE; }
<IND>{ws}*.     { if ((indtok = indent())) return indtok; }
{ws}+           { /* ignora espaços em branco */ }
":"             { return ':'; }
","             { return ','; }
"("             { return '('; }
")"             { return ')'; }
"["             { return '['; }
"]"             { return ']'; }
"+"             { return '+'; }
"-"             { return '-'; }
"*"             { return '*'; }
"%"             { return '%'; }
"="             { return '='; }
"=="            { return EQ; }
"<"             { return LT; }
">"             { return GT; }
"<="            { return LE; }
">="            { return GE; }
"!="            { return NE; }
"**"            { return POW; }
"//"            { return DIV; }
"if"            { return IF; }
"else"          { return ELSE; }
"while"         { return WHILE; }
"break"         { return BREAK; }
"continue"      { return CONTINUE; }
"return"        { return RETURN; }
"def"           { return DEF; }
"and"           { return AND; }
"or"            { return OR; }
"not"           { return NOT; }
"global"		{ return GLOBAL; }
{int}           { yylval = atoi(yytext); return INT; }
{id}            { yylval = str(yytext); return ID; }
{err}           { error(yytext); }


%%  /* ------------------------ user code ----------------------------------- */


/*
 * Inicializa a pilha de indentação e já coloca 0 no topo.
 */
void lex_init() {
    indstack.push_back(0);
    here = 1;
}


/*
 * Limpa a pilha.
 */
void lex_end() {
    indstack.clear();
}


/*
 * Requerida pelo Flex, para ele saber o que fazer quando a stream acabar.
 */
int yywrap() {
    return 1;   // encerra a análise
}


/*
 * Chamada no início de cada linha para saber se deve ser gerado um token INDENT
 * ou DEDENT. Retorna INDENT, DEDENT ou 0 (para indicar que nenhum token deve
 * ser gerado).
 */
static int indent() {
    int lvl = yyleng - 1;

    /* Devolver o caracter extra que não faz parte da indentação. */
    if (yytext[lvl] == '\n') here++;
    yyless(lvl);

    /* Se temos mais espaços que antes, coloca isso no topo da pilha de
    indentação e gera INDENT. */
    if (lvl > indstack.back()) {
        indstack.push_back(lvl);
        BEGIN(0);
        return INDENT;
    }

    /* Se temos menos espaços que antes, tira o topo da pilha, devolve os
    espaços (para serem lidos novamente, caso precise gerar vários DEDENTs
    seguidos) e gera DEDENT. */
    else if (lvl < indstack.back()) {
        indstack.pop_back();
        yyless(0);
        return DEDENT;
    }

    /* Se estamos no mesmo nível de indentação, não precisa gerar nada. */
    else {
        BEGIN(0);
        return 0;
    }
}


/*
 * Gera uma string que é uma cópia de yytext.
 */
static int str(const char *txt) {
    char *rs = (char *) malloc(strlen(txt) + 1);
    strcpy(rs, txt);
    return (int)rs;
}


/*
 * Imprime uma mensagem de erro e encerra a compilação.
 */
static void error(const char* txt) {
    fprintf(stderr, "Sequência de símbolos não reconhecida: %s\n", txt);
    exit(1);
}
